Skip to content

Conversation

@wes-myers-II
Copy link
Contributor

Summary

Workaround for Thread 1 displaying incorrect backtraces when debugging Zephyr applications.

Problem

When GDB connects to OpenOCD with RTOS awareness:

  1. GDB reads and caches live CPU registers
  2. GDB creates implicit "Thread 1" with these cached registers
  3. Later, GDB requests thread list from OpenOCD
  4. OpenOCD returns threads in kernel order (e.g., "stats" thread first)
  5. GDB assigns "stats" to Thread 1
  6. But Thread 1 already has the idle thread's registers cached

Result: Thread 1 "stats" shows idle's backtrace (arch_cpu_idle()).

Fix

Reorder the thread list so the current thread is always first. This ensures:

  • Thread 1 = current thread = the thread actually running on CPU
  • Cached registers correctly belong to Thread 1

This is a Workaround

This fix addresses the symptom, not the root cause. A proper fix would require changes to GDB:

  • GDB could invalidate cached registers when it receives thread info and discovers which thread was actually running
  • Or the RSP protocol could be extended to provide thread context before GDB caches registers

Since GDB protocol changes would require upstream GDB maintainer buy-in and could take significant time, this workaround provides immediate relief. The resulting behavior (Thread 1 = current thread) also matches most users' expectations.

Verification

Before:

* 1    Thread 0x3fcb6cd0 "stats"     arch_cpu_idle()  ← WRONG frame!
  13   Thread 0x3fcb7cf8 "idle"      _switch_restore_pc()

After:

* 1    Thread 0x3fcb7cf8 "idle"      arch_cpu_idle()  ← Correct!
  2    Thread 0x3fcb6cd0 "stats"     _switch_restore_pc()

Related

This complements PR #390 which fixes register values for non-current threads.
Both issues were discovered while debugging Zephyr on ESP32-S3.

Workaround for GDB caching live CPU registers before thread list is
available. Reorder threads so current thread is first, ensuring
Thread 1's cached registers match the actual running thread.

Signed-off-by: Wesley Myers <[email protected]>
@github-actions github-actions bot changed the title fix(rtos/zephyr): place current thread first in thread list fix(rtos/zephyr): place current thread first in thread list (OCD-1334) Jan 15, 2026
@erhankur
Copy link
Collaborator

@wes-myers-II thanks for the PR.

When the target is halted, OpenOCD reports the current thread ID to GDB. After that, GDB requests the registers for all threads one by one. Before moving forward with this change, it would be helpful to review the relevant logs to better understand the current behavior.

Additionally, if this turns out to be an issue, it should be handled in a place that applies to all RTOS implementations. In that case, the appropriate place for the fix would be rtos.c.

Could you please share the OpenOCD verbose logs (using -d3) as well as the GDB remote protocol logs? The latter can be enabled with set debug remote 1

@wes-myers-II
Copy link
Contributor Author

@wes-myers-II thanks for the PR.

When the target is halted, OpenOCD reports the current thread ID to GDB. After that, GDB requests the registers for all threads one by one. Before moving forward with this change, it would be helpful to review the relevant logs to better understand the current behavior.

Additionally, if this turns out to be an issue, it should be handled in a place that applies to all RTOS implementations. In that case, the appropriate place for the fix would be rtos.c.

Could you please share the OpenOCD verbose logs (using -d3) as well as the GDB remote protocol logs? The latter can be enabled with set debug remote 1

Hey @erhankur, I'll take a look at this and address your comments on my other PR soon. Have been pulled into another task, but will return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants